#include <stdio.h>
#include <string.h>
#include "Collection.h"

void imprimir(void* unElemento){
	printf(" %i ", *(int*)unElemento);
}

void imprimirChar(void* unElemento){
	printf("%c", *(char*)unElemento);
}

void imprimirColDeCols(void* unElemento){
	Coleccion* unaColeccion = (Coleccion*)unElemento;
	printf(" (");
	forEach(*unaColeccion, imprimir);
	printf(")");
}

void* suma(void* numeroUno, void* numeroDos){
	int* numero1 = (int*)numeroUno;
	int* numero2 = (int*)numeroDos;
	int sumaNumeros = (*numero1) + (*numero2);
	int* punteroSumaNumeros = (int*)malloc(sizeof(punteroSumaNumeros));
	(*punteroSumaNumeros) = sumaNumeros;
	return punteroSumaNumeros;
}

void* doble(void* unElemento){
	int* numero = (int*)unElemento;
	int dobleNumero = (*numero) * 2;
	int* punteroDoble = (int*)malloc(sizeof(punteroDoble));
	(*punteroDoble) = dobleNumero;
	return punteroDoble;
}

Bool esPar(void* unElemento){
	int* numero = (int*)unElemento;
	Bool esNumeroPar = (*numero) % 2 == 0;
	return esNumeroPar;
}

int main(){
	printf("- No se ha creado ninguna colección.\n\n");
	Coleccion numeros = new();
	printf("- Se ha creado la colección: ( )\n");
	printf("- Size de colección = %i.\n", size(numeros));

	int elem1 = 1;
	int elem2 = 2;
	int elem3 = 3;
	int elem4 = 4;
	int elem5 = 5;
	int elem6 = 6;
	int elem7 = 7;
	int elem8 = 8;
	int elem9 = 9;
	addElement(&numeros,&elem1);
	addElement(&numeros,&elem1);
	addElement(&numeros,&elem2);
	addElement(&numeros,&elem3);
	addElement(&numeros,&elem4);
	addElement(&numeros,&elem5);
	addElement(&numeros,&elem6);
	addElement(&numeros,&elem7);
	addElement(&numeros,&elem8);
	addElement(&numeros,&elem9);
	printf("\n- Se han agregado unos elementos en la colección.");
	printf(" (");
	forEach(numeros, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(numeros));

	int* primerElemento = (int*)first(numeros)->elemento;
	printf("\n- Primer elemento de la colección = %i.\n", *primerElemento);

	int* ultimoElemento = (int*)last(numeros)->elemento;
	printf("\n- Ultimo elemento de la colección = %i.\n", *ultimoElemento);

	removeElement(&numeros,&elem1);
	printf("\n- Se han removido unos elementos en la colección.");
	printf(" (");
	forEach(numeros, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(numeros));

	printf("\n- Todos los elementos menos el primero de la colección.");
	printf(" (");
	forEach(allButFirst(numeros), imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(allButFirst(numeros)));

	printf("\n- Todos los elementos menos el último de la colección.");
	printf(" (");
	forEach(allButLast(numeros), imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(allButLast(numeros)));

	Coleccion dobleNumeros = map(numeros, doble);
	printf("\n- El doble de cada elemento de la colección.");
	printf(" (");
	forEach(dobleNumeros, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(dobleNumeros));

	Coleccion esParNumeros = filter(numeros, esPar);
	printf("\n- Los elementos pares de la colección.");
	printf(" (");
	forEach(esParNumeros, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(esParNumeros));

	int elem0 = 0;
	printf("\n- La sumatoria de los elementos de la colección (FOLDL) = ");
	printf("%i.\n", *(int*)foldl(numeros, &elem0, suma));

	Coleccion colDoblesPares = concat(dobleNumeros, esParNumeros);
	printf("\n- Concatenacion de las coleciones Doble y Pares de numero.");
	printf(" (");
	forEach(colDoblesPares, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(colDoblesPares));

	Coleccion numeros1 = new();
	Coleccion numeros2 = new();
	Coleccion numeros3 = new();
	addElement(&numeros1,&elem1);
	addElement(&numeros2,&elem2);
	addElement(&numeros3,&elem3);
	addElement(&numeros1,&elem4);
	addElement(&numeros2,&elem5);
	addElement(&numeros3,&elem6);
	addElement(&numeros1,&elem7);
	addElement(&numeros2,&elem8);
	addElement(&numeros3,&elem9);

	Coleccion NumerosPulenta = new();
	addElement(&NumerosPulenta,&numeros1);
	addElement(&NumerosPulenta,&numeros2);
	addElement(&NumerosPulenta,&numeros3);
	printf("\n- Se ha creado una nueva coleccion con estos elementos: ");
	printf(" (");
	forEach(numeros1, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(numeros1));
	printf("\n- Se ha creado una nueva coleccion con estos elementos: ");
	printf(" (");
	forEach(numeros2, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(numeros2));
	printf("\n- Se ha creado una nueva coleccion con estos elementos: ");
	printf(" (");
	forEach(numeros3, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(numeros3));
	printf("\n- Se ha creado una nueva coleccion con estos elementos: ");
	printf(" (");
	forEach(NumerosPulenta, imprimirColDeCols);
	printf(" ) \n");
	printf("- Size de colección = %i.\n", size(NumerosPulenta));

	Coleccion* concatColDeCols = (Coleccion*)foldl1(NumerosPulenta, concate);
	printf("\n- Concatenacion de colección de colecciones.");
	printf(" (");
	forEach(*concatColDeCols, imprimir);
	printf(") \n");
	printf("- Size de colección = %i.\n", size(*concatColDeCols));

	char cadena[255];
	strcpy(cadena, "Manejo de colecciones por Fede");

	Coleccion colCadena = new();
	int i;
	for ( i = 0 ; i < strlen(cadena) ; i++ ) {
		addElement(&colCadena,&cadena[i]);
	}

	printf(" (");
	forEach(colCadena, imprimirChar);
	printf(") \n");
	printf("- Size de cadena = %i.\n", size(colCadena));


	return 0;
}
